#include "../include/lexer.hpp"


// Lexem declaration
soulc::Lexem::Lexem(soulc::LexemType type) : _type(type)
{  }

soulc::LexemType soulc::Lexem::getType()
{ return _type; }

std::string soulc::Lexem::getText()
{ return _text; }
void soulc::Lexem::setText(std::string text)
{ _text = text; }

char soulc::Lexem::getSymbol()
{ return _symbol; }
void soulc::Lexem::setSymbol(char symbol)
{ _symbol = symbol; }

int soulc::Lexem::getIntegerConst()
{ return _integerConst; }
void soulc::Lexem::setIntegerConst(int integerConst)
{ _integerConst = integerConst; }

double soulc::Lexem::getFloatConst()
{ return _floatConst; }
void soulc::Lexem::setFloatConst(double floatConst)
{ _floatConst = floatConst; }


// Lexer declaration
uint64_t soulc::Lexer::getCharNoFromStringBeginning(std::string code, uint64_t absoluteCharNo)
{
	uint64_t stringBeginnig = absoluteCharNo;

	while (stringBeginnig >= 0) {
		if (code[stringBeginnig] == '\n') {
			stringBeginnig++;
			break;
		}

		stringBeginnig--;
	}

	return absoluteCharNo - stringBeginnig;
}


std::vector<std::shared_ptr<soulc::Lexem>> soulc::Lexer::lexe(soulc::Source &source)
{
	dbg::Debug debug(true);

	debug.print(dbg::DEBUG_INFORMATION, "Lexe " + source.getFileName() + " ...");

	std::string code = source.getSource();

	std::vector<std::shared_ptr<Lexem>> lexems;

	std::string curWord = "";

	uint64_t curLine = 1;
	std::string curLineTrashSymbols;

	uint64_t i = 0;
	while (i < code.size()) {
		if (code[i] == '\n') {
			curLine++;
			curLineTrashSymbols = "";
		} else if (inList<char>(_specialSymbols, code[i])) {
			if (code[i] == '"') {
				uint64_t stringBeginnig = i;
				i++;

				std::string constStr = "";

				while (code[i] != '"') {
					if (i == code.size()) {
						raiseCompilerError(CompilerError::LEXER_SYNTAX_ERR, curLine, getCharNoFromStringBeginning(code, stringBeginnig), getCodeLine(code, curLine), "Strings doesn't end with \"");
					}

					constStr += code[i];
					i++;
				}

				lexems.push_back(std::make_shared<Lexem>(CONST_STR_LEXEM_TYPE));
				lexems.back()->setText(constStr);
			} else {
				lexems.push_back(std::make_shared<Lexem>(SPEC_SYMBOL_LEXEM_TYPE));	
				lexems.back()->setSymbol(code.at(i));
			}
		} else if (isLetter(code[i])) {
			std::string name = "";
			LexemType lexemType = IDENTIFIER_LEXEM_TYPE;

			while (!inList<char>(_specialSymbols, code[i]) && !checkForNameEnds(code[i])) {
				name += code[i];
				i++;
			
				if (inList<std::string>(_keywords, name) || inList<std::string>(_preprocessorKeywords, name)) {
					lexemType = KEYWORD_LEXEM_TYPE;
					break;
				}
			}
			i--;

			lexems.push_back(std::make_shared<Lexem>(lexemType));
			lexems.back()->setText(name);
		} else if (isDigit(code[i])) {
			LexemType lexemType = CONST_INT_LEXEM_TYPE;
			
			std::string strNumber = "";	

			while (!checkForNameEnds(code[i]) && i < code.size()) {
				if (code[i] == '.') {
					lexemType = CONST_FLOAT_LEXEM_TYPE;
					
					strNumber += '.';
					i++;

					continue;
				} else if (inList<char>(_specialSymbols, code[i])) {
					break;
				}

				strNumber += code[i];
				i++;
			}
			
			lexems.push_back(std::make_shared<Lexem>(lexemType));

			if (lexemType == CONST_INT_LEXEM_TYPE) lexems.back()->setIntegerConst(std::stoi(strNumber));
			else if (lexemType == CONST_FLOAT_LEXEM_TYPE) lexems.back()->setFloatConst(std::stof(strNumber));
		} else {
			curLineTrashSymbols += code[i];
		}

		i++;
	}

	debug.print(dbg::DEBUG_INFORMATION, "Lexe " + source.getFileName() + " done");

	return lexems;
}
